<?php
/**
 * Created by PhpStorm.
 * User: ari
 * Date: 11/16/14
 * Time: 6:49 PM
 */
namespace BC\Wallet\Bitcoin;

use CPath\Request\Executable\IExecutable;
use CPath\Request\IRequest;
use CPath\Response\Common\MapResponse;
use CPath\Response\IResponse;
use CPath\UnitTest\ITestable;
use CPath\UnitTest\IUnitTestRequest;

class VanityGenCommand implements IExecutable, ITestable
{
	const FIELD_ADDRESS = 'Address';
	const FIELD_PRIVKEY = 'Privkey';

	private $mFields = array();

	/**
	 * Execute a command and return a response. Does not render
	 * @param IRequest $Request
	 * @param String|null $prefix
	 * @throws \Exception
	 * @return IResponse the execution response
	 */
	function execute(IRequest $Request, $prefix='1') {
		$cmd = BitcoinConfig::$CMD_VANITYGEN;
		if($prefix[0] !== '1')
			$prefix = '1' . $prefix;
		$cmd .= ' ' . $prefix;

		$descriptors = array(
			0 => array("pipe", "r"), // stdin is a pipe that the child will read from
			1 => array("pipe", "w"), // stdout is a pipe that the child will write to
			2 => array("pipe", "w"), // stderr is a pipe that the child will write to
		);

		$pipes = array();
		$process=proc_open($cmd, $descriptors, $pipes);
		if (!is_resource($process))
			throw new \Exception("Command failed: " . $cmd . "\n" . print_r(error_get_last(), true));

		list(, $pstdout, $pstderr) = $pipes;

		$fields = array();
		while($line = fgets($pstdout, 1024)) {
			if(strpos($line, ': ') === false)
				continue;
			list($key, $value) = explode(': ', trim($line));
			$fields[$key] = $value;
		}

		$err = stream_get_contents($pstderr);
//		if($err)
//			throw new \Exception($err);

		if(empty($fields[self::FIELD_ADDRESS]))
			throw new \Exception("Field '" . self::FIELD_ADDRESS . "' not found in output");
		if(empty($fields[self::FIELD_PRIVKEY]))
			throw new \Exception("Field '" . self::FIELD_PRIVKEY . "' not found in output");


		proc_close($process);

		$this->mFields = $fields;
		return new MapResponse("New Address generated successfully", true, $fields);
	}

	function getGeneratedAddress() {
		if(empty($this->mFields[self::FIELD_ADDRESS]))
			throw new \Exception("Field '" . self::FIELD_ADDRESS . "' not available");
		return $this->mFields[self::FIELD_ADDRESS];
	}

	function getGeneratedPrivateKey() {
		if(empty($this->mFields[self::FIELD_PRIVKEY]))
			throw new \Exception("Field '" . self::FIELD_PRIVKEY . "' not available");
		return $this->mFields[self::FIELD_PRIVKEY];
	}

	// Static

	/**
	 * Perform a unit test
	 * @param IUnitTestRequest $Test the unit test request inst for this test session
	 * @return void
	 * @test --disable 0
	 * Note: Use doctag 'test' with '--disable 1' to have this ITestable class skipped during a build
	 */
	static function handleStaticUnitTest(IUnitTestRequest $Test) {
		$CMD = new VanityGenCommand();
		$CMD->execute($Test);
		$address = $CMD->getGeneratedAddress();
		$privKey = $CMD->getGeneratedPrivateKey();
		$Test->assert($address && true);
		$Test->assert($privKey && true);
	}
}